package searcher;

import model.core.code.CodeSeg;
import model.core.code.IEntrance;
import model.core.code.MethodData;
import model.core.graph.IToken;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.Map.Entry;

import search.model.SearchMeta;
import search.utils.DistanceUtil;

import DAO.ICodeDAO;
import DAO.IDAO;
import DAO.IWordCodeDAO;
import DAO.IWordDAO;
import DAO.mysql.MySQLDAO;

import de.linguatools.disco.DISCO;
import de.linguatools.disco.ReturnDataBN;

public class Searcher {
	private DISCO similarity;
	private IDAO dao;
	
	
	public class CodeRankable implements Comparable<CodeRankable>{
		private int score;
		private final int codeID;
		
		public CodeRankable(int codeID) {
			this.codeID = codeID;
		}
		
		public int getCodeID() {
			return codeID;
		}
		
		public void addScore(int delta) {
			score += delta;
		}
		
		@Override
		public int hashCode() {
			return codeID;
		}
		
		@Override
		public int compareTo(CodeRankable o) {
			if(codeID != o.codeID) {
				return score > o.score ? -1 : 1;
			} else {
				return 0;
			}
		}
		
	}
	
	public Searcher() {
		try {
			similarity = new DISCO("en_wiki", false);
			dao = new MySQLDAO();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void search(SearchMeta meta) {
		
	}
	
	private Set<CodeRankable> getArgRelatedCodes(List<String> wrds) {
		IWordCodeDAO wrdcodeDAO = dao.getWordCodeDAO();
		IWordDAO wrdDAO = dao.getWordDAO();
		ICodeDAO codeDAO = dao.getCodeDAO();
		List<IToken> tkens = new LinkedList<IToken>();
		for(String str : wrds) {
			tkens.add(wrdDAO.getToken(str));
		}
		List<MethodData> alternatives = new LinkedList<MethodData>();
		for(IToken tken : tkens) {
			List<IEntrance> entrs = wrdcodeDAO.getRelatedEntrance(tken);
			for(IEntrance entr : entrs) {
				if(entr != null) {
					List<MethodData> mthdDts = codeDAO.getRelatedMethod(entr.getID());
					alternatives.addAll(mthdDts);
				}
			}
		}
		//rank
		Map<Integer, CodeRankable> ranks = new HashMap<Integer, CodeRankable>();
		for(MethodData mthdDt : alternatives) {
			CodeRankable codeRkable = new CodeRankable(mthdDt.getCodeID());
			CodeRankable org = ranks.get(mthdDt.getCodeID());
			if(org == null) {
				ranks.put(mthdDt.getCodeID(), codeRkable);
			} else {
				org.addScore(1);
			}
		}
		Set<CodeRankable> result = new HashSet<CodeRankable>();
		Iterator<Entry<Integer, CodeRankable>> itr = ranks.entrySet().iterator();
		while(itr.hasNext()) {
			Entry<Integer, CodeRankable> ent = itr.next();
			result.add(ent.getValue());
		}
		return result;
	}
	
	private Set<CodeRankable> getAffectedRelatedCodes(List<String> wrds) {
		IWordCodeDAO wrdcodeDAO = dao.getWordCodeDAO();
		IWordDAO wrdDAO = dao.getWordDAO();
		ICodeDAO codeDAO = dao.getCodeDAO();
		List<IToken> tkens = new LinkedList<IToken>();
		for(String str : wrds) {
			tkens.add(wrdDAO.getToken(str));
		}
		List<MethodData> alternatives = new LinkedList<MethodData>();
		for(IToken tken : tkens) {
			List<IEntrance> entrs = wrdcodeDAO.getRelatedEntrance(tken);
			for(IEntrance entr : entrs) {
				if(entr != null) {
					List<MethodData> mthdDts = codeDAO.getRelatedMethod(entr.getID());
					alternatives.addAll(mthdDts);
				}
			}
		}
		//rank
		Map<Integer, CodeRankable> ranks = new HashMap<Integer, CodeRankable>();
		for(MethodData mthdDt : alternatives) {
			CodeRankable codeRkable = new CodeRankable(mthdDt.getCodeID());
			CodeRankable org = ranks.get(mthdDt.getCodeID());
			if(org == null) {
				ranks.put(mthdDt.getCodeID(), codeRkable);
			} else {
				org.addScore(1);
			}
		}
		Set<CodeRankable> result = new HashSet<CodeRankable>();
		Iterator<Entry<Integer, CodeRankable>> itr = ranks.entrySet().iterator();
		while(itr.hasNext()) {
			Entry<Integer, CodeRankable> ent = itr.next();
			result.add(ent.getValue());
		}
		return result;
	}
	
	private String[] getRelatedArguments(String arg, int depth) {
		return null;
	}
	
	public Set<CodeSeg> getArgumentsRelated(String[] arguments) {
		Set<CodeSeg> codes = new HashSet<CodeSeg>();
		IWordDAO wrdDAO = dao.getWordDAO();
		List<String> args = new LinkedList<String>();
		for(String arg : arguments) {
			String[] related = this.getRelatedArguments(arg, 1);
			for(String r : related) {
				args.add(r);
			}
		}
		String[] strs = new String[args.size()];
		args.toArray(strs);
		Set<CodeSeg> argumentsRelated = this.getArgumentsRelated(strs);
		return codes;
	}
}
